package com.slipper.util;

import com.slipper.core.gson.GsonUtil;
import com.slipper.exception.CommonException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapperImpl;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

public class BeanUtil {
    private static final Logger logger = LoggerFactory.getLogger(BeanUtil.class);

    public static Object getValue(Object object, String fieldName) {
        if (object == null) {
            return "";
        }

        if (object instanceof Map) {
            if (fieldName.indexOf('.') > 0) {
                String[] fieldNames = fieldName.split("\\.", 2);
                return getValue(((Map<?, ?>) object).get(fieldNames[0]), fieldNames[1]);
            } else {
                return ((Map<?, ?>) object).get(fieldName);
            }
        } else {
            if (fieldName.indexOf('.') > 0) {
                String[] fieldNames = fieldName.split("\\.", 2);
                return getValue(new BeanWrapperImpl(object).getPropertyValue(fieldNames[0]), fieldNames[1]);
            } else if (fieldName.contains("loopRow|")) {
                return "";
            } else {
                try {
                    return new BeanWrapperImpl(object).getPropertyValue(fieldName);
                } catch (Exception e) {
                    logger.error("取值失败！", e);
                    return "";
                }
            }
        }
    }

    public static <T> T copy(Object source, Class<T> target) {
        if (source == null || target == null) {
            return null;
        }
        try {
            T newInstance = target.getDeclaredConstructor().newInstance();
            BeanUtils.copyProperties(source, newInstance);
            return newInstance;
        } catch (Exception e) {
            throw new CommonException("bean复制出错！", e);
        }
    }

    public static <T, K> List<K> copyList(List<T> source, Class<K> target) {

        if (null == source || source.isEmpty()) {
            return Collections.emptyList();
        }
        return source.stream().map(e -> copy(e, target)).collect(Collectors.toList());
    }

    public static String getString(Map<String, Object> data, String key) {
        return getString(data, key, null);
    }

    public static String getString(Map<String, Object> data, String key, String defaultValue) {
        if (data == null) {
            return defaultValue;
        }

        if (!data.containsKey(key)) {
            return defaultValue;
        } else {
            Object value = data.get(key);
            return value == null ? null : value.toString();
        }
    }

    public static String[] getStrings(Map<String, Object> data, String key) {
        return getStrings(data, key, null);
    }

    public static String[] getStrings(Map<String, Object> data, String key, String[] defaultValue) {
        if (data == null) {
            return defaultValue;
        }

        Object value = data.get(key);
        if (value == null) {
            return defaultValue;
        } else if (value instanceof List<?> list) {
            return list.stream().map(Object::toString).toList().toArray(new String[0]);
        } else {
            return (String[]) value;
        }
    }

    public static Boolean getBoolean(Map<String, Object> data, String key, Boolean defaultValue) {
        if (data == null) {
            return defaultValue;
        }

        Object value = data.get(key);
        if (value == null) {
            return defaultValue;
        } else {
            return (Boolean) value;
        }
    }

    public static Integer getInteger(Map<String, Object> data, String key, Integer defaultValue) {
        if (data == null) {
            return defaultValue;
        }

        Object value = data.get(key);
        if (Tool.isBlank(value)) {
            return defaultValue;
        } else {
            return Integer.parseInt(value.toString());
        }
    }

    public static Integer getInteger(Map<String, Object> data, String key) {
        if (data == null) {
            return null;
        }

        Object value = data.get(key);
        if (Tool.isBlank(value)) {
            return null;
        } else {
            return (int) Double.parseDouble(value.toString());
        }
    }

    public static BigDecimal getBigDecimal(Map<String, Object> data, String key, BigDecimal defaultValue) {
        if (data == null) {
            return defaultValue;
        }

        Object value = data.get(key);
        if (Tool.isBlank(value)) {
            return defaultValue;
        } else {
            return new BigDecimal(value.toString());
        }
    }

    public static Date getDate(Map<String, Object> data, String key, Date defaultValue) {
        if (data == null) {
            return defaultValue;
        }

        Object value = data.get(key);
        if (!Tool.isBlank(value)) {
            try {
                return DateUtil.parseDate(value.toString());
            } catch (Exception e) {
                logger.error("日期转换出错！", e);
            }
        }
        return defaultValue;
    }

    public static <T> List<T> toList(List<Map<String, Object>> sourceList, Class<T> clazz) {
        List<T> resultList = new ArrayList<>();
        sourceList.forEach(source -> resultList.add(cn.hutool.core.bean.BeanUtil.toBean(source, clazz)));
        return resultList;
    }

    public static boolean isSame(Map<String, Object> newMap, Map<String, Object> oldMap, List<String> filterList) {
        for (Map.Entry<String, Object> entry : newMap.entrySet()) {
            if (filterList.contains(entry.getKey())) continue;

            if (!oldMap.containsKey(entry.getKey())) return false;
            if (entry.getValue() == null && oldMap.get(entry.getKey()) != null) return false;
            if (entry.getValue() != null && oldMap.get(entry.getKey()) == null) return false;
            if (entry.getValue() != null && oldMap.get(entry.getKey()) != null
                    && !entry.getValue().equals(oldMap.get(entry.getKey()))) return false;
        }
        return true;
    }

    public static Map<String, Object> toLowerCaseKey(Map<String, Object> dataMap) {
        if (dataMap == null || dataMap.isEmpty()) return dataMap;
        Map<String, Object> resultMap = new HashMap<>();
        dataMap.forEach((key, value) -> resultMap.put(key.toLowerCase(), value));
        return resultMap;
    }

    public static List<Map<String, Object>> toLowerCaseKey(List<Map<String, Object>> dataList) {
        if (dataList == null || dataList.isEmpty()) return dataList;
        List<Map<String, Object>> resultList = new ArrayList<>();
        dataList.forEach(dataMap -> {
            if (dataMap == null || dataMap.isEmpty()) return;
            Map<String, Object> resultMap = new HashMap<>();
            dataMap.forEach((key, value) -> resultMap.put(key.toLowerCase(), value));
            resultList.add(resultMap);
        });
        return resultList;
    }

    public static <T> List<T> setOrdinal(List<T> list) {
        return setOrdinal(list, 0, "ordinal");
    }

    public static <T> List<T> setOrdinal(List<T> list, int start) {
        return setOrdinal(list, start, "ordinal");
    }

    public static <T> List<T> setOrdinal(List<T> list, int start, String property) {
        int index = start;
        for (Object obj : list) {
            BeanWrapperImpl wrapper = new BeanWrapperImpl(obj);
            wrapper.setPropertyValue(property, index++);
        }
        return list;
    }

    public static String concatMapJson(String ...args) {
        if (args == null || args.length == 0) return null;
        if (args.length == 1) return args[0];

        Map<String, Object> dataMap = null;
        for (String arg : args) {
            if (Tool.isBlank(arg)) continue;
            if (dataMap == null) {
                dataMap = GsonUtil.toMap(arg);
            } else {
                Map<String, Object> map = GsonUtil.toMap(arg);
                if (map != null) {
                    dataMap.putAll(map);
                }
            }
        }
        return dataMap == null ? null : GsonUtil.toJson(dataMap);
    }
}
